package com.ecoolex.discount.sales.core.manager;

import com.ecoolex.discount.sales.core.dao.DiscountProductInventoryDAO;
import com.ecoolex.discount.sales.entity.*;
import com.ecoolex.discount.sales.entity.DiscountProductInventory.Column;
import com.ecoolex.discount.sales.entity.DiscountProductInventoryExample.Criteria;
import com.ecoolex.discount.sales.enums.*;
import com.ecoolex.discount.sales.pojo.AddDiscountProductInventoryDTO;
import com.ecoolex.discount.sales.pojo.EditDiscountProductInventoryDTO;
import com.ecoolex.discount.sales.pojo.QueryDiscountProductInventoryDTO;
import com.ecoolex.framework.common.pojo.Page;
import com.ecoolex.framework.common.pojo.Pagination;
import com.ecoolex.framework.common.pojo.Sorting;
import com.ecoolex.framework.common.pojo.Sortings;
import com.ecoolex.framework.common.util.BizAssert;
import com.ecoolex.framework.common.util.Check;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static com.ecoolex.discount.sales.entity.DiscountProductInventory.IS_DELETED;
import static com.ecoolex.discount.sales.entity.DiscountProductInventory.NOT_DELETED;

@Service
public class DiscountProductInventoryManager {
    @Autowired
    private DiscountProductInventoryDAO dao;

    @Autowired
    private DiscountProductManager discountProductManager;
    
    @Autowired
    private DiscountOrderDetailManager discountOrderDetailManager;
    
    @Autowired
    private DiscountProductAttachManager discountProductAttachManager;
    
    @Autowired
    private DiscountProductVouchersManager discountProductVouchersManager;
    
    public Long productInventory(Integer productId) {
    	DiscountProductInventoryExample example = new DiscountProductInventoryExample();
    	Criteria criteria = example.createCriteria();
    	criteria.andProductIdEqualTo(productId)
    	.andStatusEqualTo(DiscountProductInventoryStatus.UNUSED.real())
    	.andDeletedEqualTo(DiscountProductInventory.NOT_DELETED);
		return dao.countByExample(example);
	}

    public DiscountProductInventory getById(Integer inventoryId) {
        return dao.selectByPrimaryKeyWithLogicalDelete(inventoryId, NOT_DELETED);
    }

    public Pagination<DiscountProductInventory> query(QueryDiscountProductInventoryDTO query, Sorting[] sorts, Page page) {
        DiscountProductInventoryExample example = new DiscountProductInventoryExample();
        Criteria criteria = example.createCriteria();
        
        if(Check.notNull(query.getProductId())) {
        	criteria.andProductIdEqualTo(query.getProductId());
        }
        if (Check.notNullOrTrimEmpty(query.getVoucherNumber())) {
            criteria.andVoucherNumberEqualTo(query.getVoucherNumber());
        }
        criteria.andDeletedEqualTo(NOT_DELETED);
        example.orderBy(Sortings.builder(sorts).verify(Column::valueOf).toSql());
        example.setOffset(page.getFirstIndex());
        example.setRows(page.getPageSize());

        return Pagination.create(page, dao.countByExample(example), () -> dao.selectByExample(example));
    }

    public boolean existByProductIdAndVoucherNumber(Integer productId, String voucherNumber) {
        DiscountProductInventoryExample example = new DiscountProductInventoryExample();
        example.createCriteria()
                .andProductIdEqualTo(productId)
                .andVoucherNumberEqualTo(voucherNumber);
        return dao.countByExample(example) > 0;
    }

    private DiscountProductInventory convert(Integer productId, AddDiscountProductInventoryDTO add, String createUser) {
        DiscountProductInventory record = new DiscountProductInventory();
        record.setProductId(productId);
        record.setVoucherNumber(add.getVoucherNumber());
        record.setVoucherPass(add.getVoucherPass());
        record.setStatus(DiscountProductInventoryStatus.UNUSED.real());
        record.setDeleted(NOT_DELETED);
        record.setCreateUser(createUser);
        record.setCreateTime(Date.from(Instant.now()));
        record.setUpdateUser(createUser);
        record.setUpdateTime(Date.from(Instant.now()));
        return record;
    }

    public void validityVerify(DiscountProduct product) {
        BizAssert.isTrue(Check.isNullOrTrimEmpty(product.getServiceDataId()), "服务数据Id必须为空");
    }

    public void onlineVerify(DiscountProduct product, DiscountProductGiftCard record) {
        validityVerify(product);

        BizAssert.isTrue(DiscountProductGiftCardCounterPriceType.FIXED.equal(record.getCounterPriceType()), "价格类型不能为空并且只能为固定价格类型");
        BizAssert.isTrue(Check.notNullAndGtZero(record.getMaxBuyNumber()), "最大购买数量不能空并且大于0");
        BizAssert.isTrue(Check.notNull(record.getCounterPrice()), "专柜价不能为空");
        BizAssert.isTrue(Check.notNullAndGtZero(record.getRetailPrice()), "零售价不能为空并且大于零");
        //BizAssert.isTrue(record.getRetailPrice().scale() <= 2, "零售价只支持最大2位小数设置");
    }

    public void onlineVerify(DiscountProduct product, DiscountProductVouchers vouchers) {
        validityVerify(product);

        BizAssert.isTrue(Check.notNull(vouchers.getCounterPrice()), "专柜价不能为空");
        BizAssert.isTrue(Check.notNullAndGtZero(vouchers.getRetailPrice()), "零售价不能为空并且要大于0");
        //BizAssert.isTrue(vouchers.getRetailPrice().scale() <= 2, "零售价只支持最大2位小数设置");
        BizAssert.isTrue(Check.notNullAndGtZero(vouchers.getMaxBuyNumber()), "最大购买数量不能为空并且要大于0");
        BizAssert.isTrue(Check.notNull(vouchers.getExpirydateStrategy()), "有效期策略不能为空");
        // 有效期策略
        if (DiscountProductVouchersExpirydateStrategy.FIXED.equal(vouchers.getExpirydateStrategy())) {
            BizAssert.isTrue(Check.notNull(vouchers.getFixedEndExpirydate()), "固定结束有效期不能为空");
            if (Check.notNull(vouchers.getFixedStartExpirydate())) {
                BizAssert.isTrue(vouchers.getFixedStartExpirydate().before(vouchers.getFixedEndExpirydate()), "固定开始时间必须在结束时间之前");
            }
        } else if (DiscountProductVouchersExpirydateStrategy.DYNAMIC.equal(vouchers.getExpirydateStrategy())) {
            BizAssert.isTrue(Check.notNull(DiscountProductVouchersDynamicExpirydateType.realValueOf(vouchers.getDynamicExpirydateType())), "动态有效期类型不能空");
            BizAssert.isTrue(Check.notNullAndGtZero(vouchers.getDynamicExpirydateValue()), "动态有效期值不能空并且大于0");
        }
    }

    private void verify(Integer productId, AddDiscountProductInventoryDTO add) {
        BizAssert.isTrue(Check.notNull(add.getVoucherNumber()), "券码不能为空");
        BizAssert.isTrue(!existByProductIdAndVoucherNumber(productId, add.getVoucherNumber()), "券码[{}]在产品中已经存在", add.getVoucherNumber());
    }


    public DiscountProductInventory add(Integer productId, AddDiscountProductInventoryDTO add, String createUser) {
        DiscountProductWithBLOBs product = discountProductManager.getById(productId);
        BizAssert.isTrue(Check.notNull(product), "产品不存在");
        BizAssert.isTrue(DiscountProductServiceType.INVENTORY.equal(product.getServiceType()), "产品的服务类型不支持添加库存");

        verify(productId, add);
        DiscountProductInventory record = convert(productId, add, createUser);
        dao.insert(record);
        return record;
    }

    public void batchAdd(Integer productId, List<AddDiscountProductInventoryDTO> addList, String createUser) {
        DiscountProductWithBLOBs product = discountProductManager.getById(productId);
        BizAssert.isTrue(Check.notNull(product), "产品不存在");
        BizAssert.isTrue(DiscountProductServiceType.INVENTORY.equal(product.getServiceType()), "产品的服务类型不支持添加库存");

        List<DiscountProductInventory> recordList = addList.stream()
                .map(add -> {
                    verify(productId, add);
                    return convert(productId, add, createUser);
                }).collect(Collectors.toList());
        dao.batchInsert(recordList);
    }

    @Transactional
    public void update(Integer inventoryId, EditDiscountProductInventoryDTO edit, String updateUser) {
        DiscountProductInventory record = new DiscountProductInventory();
        record.setVoucherPass(edit.getVoucherPass());
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        DiscountProductInventoryExample example = new DiscountProductInventoryExample();
        example.createCriteria()
                .andInventoryIdEqualTo(inventoryId)
                .andStatusEqualTo(DiscountProductInventoryStatus.UNUSED.real())
                .andDeletedEqualTo(NOT_DELETED);

        int row = dao.updateByExampleSelective(record,
                example,
                Column.voucherPass,
                Column.updateUser,
                Column.updateTime);

        BizAssert.isTrue(row == 1, "修改失败");
    }


    public void invalid(Integer inventoryId, String updateUser) {
        DiscountProductInventory record = new DiscountProductInventory();
        record.setStatus(DiscountProductInventoryStatus.INVALID.real());
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        DiscountProductInventoryExample example = new DiscountProductInventoryExample();
        example.createCriteria()
                .andInventoryIdEqualTo(inventoryId)
                .andStatusEqualTo(DiscountProductInventoryStatus.UNUSED.real())
                .andDeletedEqualTo(NOT_DELETED);

        int row = dao.updateByExampleSelective(record,
                example,
                Column.status,
                Column.updateUser,
                Column.updateTime);

        BizAssert.isTrue(row == 1, "作废失败");
    }

    public void delete(Integer inventoryId, String updateUser) {
        DiscountProductInventory record = new DiscountProductInventory();
        record.setDeleted(IS_DELETED);
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        DiscountProductInventoryExample example = new DiscountProductInventoryExample();
        example.createCriteria()
                .andInventoryIdEqualTo(inventoryId)
                .andStatusEqualTo(DiscountProductInventoryStatus.UNUSED.real())
                .andDeletedEqualTo(NOT_DELETED);

        int row = dao.updateByExampleSelective(record,
                example,
                Column.deleted,
                Column.updateUser,
                Column.updateTime);

        BizAssert.isTrue(row == 1, "删除失败");
    }

    @Transactional
    public boolean freeze(DiscountOrder order, String updateUser) {
    	boolean flag = dao.freeze(order.getOrderNo(),
            DiscountProductInventoryStatus.FREEZE.real(),
            updateUser,
            order.getProductId(),
            DiscountProductInventoryStatus.UNUSED.real(),
            order.getBuyNumber()) == order.getBuyNumber();
    	if(false == flag) {
			return flag;
		}
    	List<DiscountProductAttach> attachList = discountProductAttachManager.listByMainProductId(order.getProductId());
    	if(Check.notNullOrEmpty(attachList)) {
    		for (DiscountProductAttach attach : attachList) {
    			flag = dao.freeze(order.getOrderNo(),
                    DiscountProductInventoryStatus.FREEZE.real(),
                    updateUser,
                    attach.getAttachProductId(),
                    DiscountProductInventoryStatus.UNUSED.real(),
                    order.getBuyNumber()) == order.getBuyNumber();
    			if(false == flag) {
    				return flag;
    			}
			}
    	}
    	return flag;
    }

    @Transactional
    public void unfreeze(DiscountOrder order, String updateUser) {
        dao.unfreeze(order.getOrderNo(),
                DiscountProductInventoryStatus.UNUSED.real(),
                updateUser,
                order.getProductId(),
                DiscountProductInventoryStatus.FREEZE.real());
        List<DiscountProductAttach> attachList = discountProductAttachManager.listByMainProductId(order.getProductId());
    	if(Check.notNullOrEmpty(attachList)) {
    		for (DiscountProductAttach attach : attachList) {
    			dao.unfreeze(order.getOrderNo(),
                    DiscountProductInventoryStatus.UNUSED.real(),
                    updateUser,
                    attach.getAttachProductId(),
                    DiscountProductInventoryStatus.FREEZE.real());
			}
    	}
    }

    @Transactional
    public boolean deduct(DiscountOrder order, String updateUser) {
        boolean flag =  dao.deduct(order.getOrderNo(),
                DiscountProductInventoryStatus.USED.real(),
                updateUser,
                order.getProductId(),
                DiscountProductInventoryStatus.FREEZE.real()) == order.getBuyNumber();
        if(false == flag) {
			return flag;
		}
    	List<DiscountProductAttach> attachList = discountProductAttachManager.listByMainProductId(order.getProductId());
    	if(Check.notNullOrEmpty(attachList)) {
    		for (DiscountProductAttach attach : attachList) {
    			flag =  dao.deduct(order.getOrderNo(),
                    DiscountProductInventoryStatus.USED.real(),
                    updateUser,
                    attach.getAttachProductId(),
                    DiscountProductInventoryStatus.FREEZE.real()) == order.getBuyNumber();
    			if(false == flag) {
    				return flag;
    			}
			}
    	}
    	return flag;
    }

    private List<DiscountProductInventory> queryUsedByUsedTransNo(String usedTransNo) {
        DiscountProductInventoryExample example = new DiscountProductInventoryExample();
        example.createCriteria()
                .andStatusEqualTo(DiscountProductInventoryStatus.USED.real())
                .andUsedTransNoEqualTo(usedTransNo)
                .andDeletedEqualTo(NOT_DELETED);

        return dao.selectByExample(example);
    }

    public void processOrder(DiscountOrder order, DiscountProductGiftCard giftCard, String updateUser) {
        BizAssert.isTrue(deduct(order, updateUser), "扣除库存失败");

        List<DiscountProductInventory> inventoryList = queryUsedByUsedTransNo(order.getOrderNo());

        // 生成卡券
        List<DiscountOrderDetail> detailList = inventoryList.stream().map(inventory -> {
            DiscountOrderDetail detail = new DiscountOrderDetail();
            detail.setTransNo(order.getOrderNo());
            detail.setVoucherNumber(inventory.getVoucherNumber());
            detail.setVoucherPass(inventory.getVoucherPass());
            detail.setProductId(giftCard.getProductId());
            if(giftCard.getProductId().equals(inventory.getProductId())) {
            	detail.setIsMainProduct(true);
            }else {
            	detail.setIsMainProduct(false);
            }
            return detail;
        }).collect(Collectors.toList());
        discountOrderDetailManager.add(order, detailList, updateUser);
    }

    public void processOrder(DiscountOrder order, DiscountProductVouchers vouchers, String updateUser) {
        BizAssert.isTrue(deduct(order, updateUser), "扣除库存失败");

        List<DiscountProductInventory> inventoryList = queryUsedByUsedTransNo(order.getOrderNo());
        List<DiscountOrderDetail> detailList = inventoryList.stream().map(inventory -> {
            DiscountOrderDetail detail = new DiscountOrderDetail();
            detail.setProductId(inventory.getProductId());
            detail.setTransNo(order.getOrderNo());
            detail.setVoucherNumber(inventory.getVoucherNumber());
            detail.setVoucherPass(inventory.getVoucherPass());
            if(vouchers.getProductId().equals(inventory.getProductId())) {
            	detail.setIsMainProduct(true);
            }else {
            	detail.setIsMainProduct(false);
            }
            return detail;
        }).collect(Collectors.toList());
        Date effectivetime = null;
        Date expiretime = null;
        // 计算主券有效期
        if (DiscountProductVouchersExpirydateStrategy.FIXED.equal(vouchers.getExpirydateStrategy())) {
            effectivetime = vouchers.getFixedStartExpirydate();
            expiretime = vouchers.getFixedEndExpirydate();
        } else if (DiscountProductVouchersExpirydateStrategy.DYNAMIC.equal(vouchers.getExpirydateStrategy())) {
            DiscountProductVouchersDynamicExpirydateType type = DiscountProductVouchersDynamicExpirydateType.realValueOf(vouchers.getDynamicExpirydateType());
            if (type == DiscountProductVouchersDynamicExpirydateType.DAY) {
                expiretime = Date.from(Instant.now().plus(vouchers.getDynamicExpirydateValue(), ChronoUnit.DAYS));
            } else if (type == DiscountProductVouchersDynamicExpirydateType.HOURS) {
                expiretime = Date.from(Instant.now().plus(vouchers.getDynamicExpirydateValue(), ChronoUnit.HOURS));
            } else if (type == DiscountProductVouchersDynamicExpirydateType.YEAR) {
                expiretime = Date.from(Instant.now().plus(vouchers.getDynamicExpirydateValue()*365, ChronoUnit.DAYS));
            } else if (type == DiscountProductVouchersDynamicExpirydateType.MONTH) {
                expiretime = Date.from(Instant.now().plus(vouchers.getDynamicExpirydateValue()*30, ChronoUnit.DAYS));
            }
        }
        for(DiscountOrderDetail detail : detailList) {
        	if(detail.getProductId().equals(vouchers.getProductId())) {
        		detail.setEffectivetime(effectivetime);
        		detail.setExpiretime(expiretime);
        	}
        }
        //查询关联的附加券
        List<DiscountProductAttach> attachList = discountProductAttachManager.listByMainProductId(order.getProductId());
        if(Check.notNullOrEmpty(attachList)) {
    		for (DiscountProductAttach attach : attachList) {
    			DiscountProductVouchers attachVochers = discountProductVouchersManager.getByProductId(attach.getAttachProductId());
    			if(Check.notNull(attachVochers)) {
    				// 计算附加券有效期
        	        if (DiscountProductVouchersExpirydateStrategy.FIXED.equal(attachVochers.getExpirydateStrategy())) {
        	            effectivetime = attachVochers.getFixedStartExpirydate();
        	            expiretime = attachVochers.getFixedEndExpirydate();
        	        } else if (DiscountProductVouchersExpirydateStrategy.DYNAMIC.equal(attachVochers.getExpirydateStrategy())) {
        	            DiscountProductVouchersDynamicExpirydateType type = DiscountProductVouchersDynamicExpirydateType.realValueOf(attachVochers.getDynamicExpirydateType());
        	            if (type == DiscountProductVouchersDynamicExpirydateType.DAY) {
        	                expiretime = Date.from(Instant.now().plus(attachVochers.getDynamicExpirydateValue(), ChronoUnit.DAYS));
        	            } else if (type == DiscountProductVouchersDynamicExpirydateType.HOURS) {
        	                expiretime = Date.from(Instant.now().plus(attachVochers.getDynamicExpirydateValue(), ChronoUnit.HOURS));
        	            } else if (type == DiscountProductVouchersDynamicExpirydateType.YEAR) {
        	                expiretime = Date.from(Instant.now().plus(attachVochers.getDynamicExpirydateValue()*365, ChronoUnit.DAYS));
        	            } else if (type == DiscountProductVouchersDynamicExpirydateType.MONTH) {
        	                expiretime = Date.from(Instant.now().plus(attachVochers.getDynamicExpirydateValue()*30, ChronoUnit.DAYS));
        	            }
        	        }else {
        	        	effectivetime = null;
        	        	expiretime = null;
        	        }
    			}
    			for(DiscountOrderDetail detail:detailList) {
    	        	if(detail.getProductId().equals(attachVochers.getProductId())) {
    	        		detail.setEffectivetime(effectivetime);
    	        		detail.setExpiretime(expiretime);
    	        	}
    	        }
    		}
    	}
        // 生成卡券
        discountOrderDetailManager.add(order, detailList, updateUser);
    }


}